#!/usr/bin/env python
from Combat2 import clsCombat
from bdd import *
from google.appengine.api import users
import random
from xml.dom.minidom import Document
from yaml import load, dump
    
class clsBases:
    ############################################################################
    ############################################################################
    ## Methodes d'Initialisations
    ############################################################################
    ############################################################################
    def __init__(self,keyPartie=None):
        # la seule chose a initialiser la clee de la partie
        if keyPartie == None :	self.keyPartie = -1
        else:			self.keyPartie = db.Key(keyPartie)

    def connecteJoueurEtPartie(self,id=None):
        """Recupere la partie en fonction du user"""
        if id == None :
            identifiant = users.get_current_user()
            if (identifiant == None) : self.redirect(users.create_login_url(self.request.uri))
        else:
            identifiant = db.Users(id)
        
        joueurs = dbJoueur().all()
        joueurs.filter("identifiant =", identifiant)
        joueur = joueurs.get()
        
        self.docXml = Document()
        data = self.docXml.createElement("data")
        self.docXml.appendChild(data)

        joueurData = self.docXml.createElement("joueur")
        partieData = self.docXml.createElement("partie")
        
        if joueur != None :
            joueurData.setAttribute("key", str(joueur.key()))
            joueurData.setAttribute("nom", joueur.nom)
            joueurData.setAttribute("titre", joueur.keyTitre.nom)
            joueurData.setAttribute("royaume", joueur.keyRoyaume.nom)
            joueurData.setAttribute("argent", str(joueur.keyUsurier.argent))
            joueurData.setAttribute("numeroInsurge", str(joueur.numeroInsurge))
            
            partieData.setAttribute("key",str(joueur.keyPartie.key()))
            partieData.setAttribute("tour",str(joueur.keyPartie.tour))
        
        data.appendChild(partieData)
        data.appendChild(joueurData)
        
        return self.docXml.toprettyxml()

    def recupereRegion(self,keyPartie):
        regions = dbRegion().all()
        regions.filter("keyPartie =",db.Key(keyPartie))

        self.docXml = Document()
        data = self.docXml.createElement("data")
        self.docXml.appendChild(data)

        if regions != None:
            for region in regions:
                regionData = self.docXml.createElement("regionData")

                regionData.setAttribute("key", str(region.key()))
                regionData.setAttribute("nom", region.nom)
                regionData.setAttribute("etat", str(region.etat))
                regionData.setAttribute("type", str(region.type))
                regionData.setAttribute("morale", str(region.morale))
                regionData.setAttribute("meteo", str(region.meteo))
                regionData.setAttribute("royaume", region.keyRoyaume.nom)
                
                armees = dbArmee().all()
                armees.filter("keyRegion =",region.key())

                if armees.count() > 0 :
                    
                    for armee in armees:
                        armeeData = self.docXml.createElement("armeeData")
                        
                        armeeData.setAttribute("key", str(armee.key()))
                        armeeData.setAttribute("keyJoueur", str(armee.keyJoueur.key()))
                        armeeData.setAttribute("sequenceCombat", str(armee.sequenceCombat))
                        armeeData.setAttribute("precedenteRegion", str(armee.precedenteRegion))

                        regionData.appendChild(armeeData)
                
                data.appendChild(regionData)

        return self.docXml.toprettyxml()

    def cherchePartieAvecIdentifiant(self,identifiant):
        """Cherche la partie auxquel jous le joueur en fonction de son identifiant(user)"""
        j = dbJoueur().all()
        j.filter("identifiant =",identifiant)
        resJ = j.get()
        
        if resJ == None : return False
        else :         
            self.keyPartie = resJ.keyPartie     
            return True

    def reprendrePartie(self,keyPartie):
        """ initialyse la keyPartie (obsolete ??)"""
        self.keyPartie = keyPartie

    def ajouteJoueur(self,nom,royaumeChoisie,titreChoisie="Chevalier",argent=0,numeroInsurge=0):
        # les requetes pour clee de table titre / Royaume
        titre = dbTitre()
        royaume = dbRoyaume()

        queryT = titre.all()
        queryF = royaume.all()
        queryF.filter("nom =",royaumeChoisie)
        queryF.filter("keyPartie =",self.keyPartie)
        qf = queryF.get()

        #-------------------------------------------------
        # creation d'un joueur
        #-------------------------------------------------
        # Son compte :
        usurier = dbUsurier()
        usurier.argent = argent
        keyUsurier = usurier.put()
        
        # Sa localisation :
        localisation = dbLocalisation()
        localisation.courante = "Chateau"
        keyLocalisation = localisation.put()
        
        joueur = dbJoueur()
        joueur.identifiant = users.get_current_user()
        joueur.nom = nom
        joueur.argent = int(argent)
        joueur.numeroInsurge = int(numeroInsurge)
        joueur.keyPartie = self.keyPartie
        joueur.keyTitre = queryT.filter("nom =",titreChoisie).get().key() # Par defaut
        joueur.keyRoyaume = qf.key()
        joueur.keyLocalisation = keyLocalisation
        joueur.keyUsurier = keyUsurier
        keyJoueur = joueur.put()
        
        self.ajouteArmee(keyJoueur,qf.regionDepart)

    def ajouteArmee(self,keyJoueur,nomRegion,sequenceCombat=""):
        """ Ajoute une armee sur le nom d'une region"""
        armee = dbArmee()
        armee.keyJoueur = keyJoueur
        armee.sequenceCombat = sequenceCombat
        
        clee = dbRegion.all().filter("nom =",nomRegion).get()
        if clee != None :
            armee.keyRegion = clee.key()
            armee.precedenteRegion = clee.nom
            armee.put()

    def startStop(self):
        """ Demmare ou coupe une partie..."""
        partie = dbPartie().all()
        partie.filter("__key__ =", self.keyPartie )
        resultat = partie.get()
        
        if resultat.run:    resultat.run = False
        else:		    resultat.run = True
        
        resultat.put()

    def initGlobal():
        """Les tables minimum sans lesquelles aucunes partie ne pourrait debuter"""
        titres= [{"nom":"Roi","part":5,"attribution":""},
                {"nom":"Duc","part":4,"attribution":""},
                {"nom":"Compte","part":3,"attribution":""},
                {"nom":"Baron","part":2,"attribution":""},
                {"nom":"Chevalier","part":1,"attribution":""}]

#	titres = dump(load('/config/titres.yaml'))

        if dbTitre.all().count() == 0 :
            # creation table titre
            for titre in titres:
                ttemp = dbTitre(nom=titre['nom'],salaireMin=titre['part'],attribution=titre['attribution'])
                ttemp.put()


    def nouvellePartie(self,nbOrdre=6,maxJoueur=6):
        """ Cree une partie, cree la table commune (au cas ou elle n'existe pas)"""
        self.initGlobal()       	# on s'assure qu'il y ai au moins les tables standards
        p = dbPartie()          	# On lance la nouvelle partie
        p.nbOrdre = nbOrdre  
        p.maxJoueurPF = maxJoueur
        p.run = False

        self.keyPartie = p.put()   	# on recupere l'id
        return self.keyPartie
    
    def initRoyaume(self):
        """ Creation de la table des royaumes"""
        royaumes = [ ["France","Languedoc"],
                    ["Angleterre","Haute Normandie"],
                    ["Bretagne","Bretagne"],
                    ["Flandres","Flandre"],
                    ["Bourgogne","Compte de bourgogne"],
                    ["Navarre","Auxerois"],
                    ["Neutre",""],
                    ["Revolte",""]]
        
#	royaumes = yaml.dump(yaml.load('/config/royaumes.yaml'))
	
	# creation table Royaume
	#for royaume in royaumes:
	#    ftemp = dbRoyaume(nom=royaume['nom'],regionDepart=royaume['regionDepart'],keyPartie=self.keyPartie)
	for nomRoyaume,regionDepartRoyaume in royaumes:
		ftemp = dbRoyaume(nom=nomRoyaume,regionDepart=regionDepartRoyaume,keyPartie=self.keyPartie)
		ftemp.put()

    def initRegion(self):
        regions =  [["Bretagne",0],
                   ["Basse Normandie",0],
                   ["Haute Normandie",0],
                   ["Pas de Calais",0],
                   ["Flandre",0],
                   ["Ardennes",0],
                   ["Anjou",0],
                   ["Touraine",0],
                   ["Orleannais",0],
                   ["Ile de France",0],
                   ["Artois",0],
                   ["Auxerois",0],
                   ["Champagne",0],
                   ["Compte de Bourgogne",0],
                   ["Duche de Bourgogne",0],
                   ["Berry",0],
                   ["Poitou",0],
                   ["Saintonge",0],
                   ["Limousin",0],
                   ["Auvergne",0],
                   ["Dauphine",0],
                   ["Provence",0],
                   ["Languedoc",0],
                   ["Armagnac",0],
                   ["Bearn",0],
                   ["Guyenne",0],
                   ["Navarre",0],
                   ["Roussillon",0]]

#	regions = yaml.dump(yaml.load('/config/regions.yaml'))
	
        # creation table region
        royaumeNeutre = dbRoyaume.all().filter("nom =","Neutre").get()
        
        #for region in regions:
        #    rtemp = dbRegion(nom=region['nom'],type=region['type'],keyPartie=self.keyPartie,etat=0,meteo=0,morale=100)
        for nomRegion,typeRegion in regions:
            rtemp = dbRegion(nom=nomRegion,type=typeRegion,keyPartie=self.keyPartie,etat=0,meteo=0,morale=100)
            # On cherche si une Royaume a sa region de depart ici donc on ne place pas de paysans
            royaume = dbRoyaume.all().filter("regionDepart =",nomRegion).get()
            
            if royaume != None :
                rtemp.keyRoyaume = royaume.key()
                rtemp.put()
            else :
                # pas de Royaume, un petit commite d'acceuil alors :-)
                rtemp.keyRoyaume = royaumeNeutre.key()
                rtemp.put()
    
    def razBases():
        clsBases.raz(dbJoueur.all())
        clsBases.raz(dbPartie.all())
        clsBases.raz(dbRoyaume.all())
        clsBases.raz(dbTitre.all())
        clsBases.raz(dbArmee.all())
        clsBases.raz(dbRegion.all())
        clsBases.raz(dbResultatCombat.all())
        clsBases.raz(dbGeoles.all())

    def raz(base):
        for d in base: d.delete()

    ############################################################################
    ############################################################################
    ## Methodes combats/guerres
    ############################################################################
    ############################################################################
    def gereTour():
        """Gere le tour en cours de toute les parties"""
        parties = dbPartie().all()
        parties.filter("run =",True)		# On ne veux que les parties qui ne sont pas en pause
        
        ###################################
        # Pour toutes les parties
        ###################################
        for partie in parties :
            # On parcours toutes les regions de la partie cours
            regions = dbRegion().all()
            regions.filter("keyPartie =",partie.key())
            ###################################
            # Pour toutes les regions
            ###################################
            for region in regions:
                # on recupere les armees de joueur et present sur la region
                armees = dbArmee.all()
                armees.filter("keyRegion =", region.key())
                armees.order("-date")
                
                # Trois(voir quatre) possibilites de combat :
                # - La region est neutre ou revolte, on combat un petit groupe de paysans
                # - Il y'a une armee ennemie sur la region
                # - La region est ennemie et il y a une garnison
                # - Neutre + armees ennemies (mais c'est une combinaison)

                # Mais pour commencer il faut au moins une armee
                if armees.count() > 0 :
                    combat = clsCombat(partie.nbOrdre,region.nom,region.type,region.meteo)

                    # Gestion du neutre ou du revolte
                    if region.keyRoyaume.nom == "Neutre" :
                        combat.ajouteArmee("Paysans","Neutre",clsBases.armeeAleatoire(partie.nbOrdre,"j",10))
                    elif region.keyRoyaume.nom == "Revolte" :
                            combat.ajouteArmee("Revolte","Revolte",clsBases.armeeAleatoire(partie.nbOrdre,"jdm",13))

		    # on y met les armees dirige par des joueurs
		    for armee in armees: combat.ajouteArmee(armee.keyJoueur.nom,armee.keyJoueur.keyRoyaume.nom,armee.sequenceCombat)

                    # Ici normalement toutes les armees en presence sont presente :-)
                    if combat.testSiGuerre() :
                        # on stock le resultat du combat  
                        clsBases.sauveCombat(combat.laGuerre(),partie.tour,region)

		###################################
		# fin de gestion de la region
		###################################
		# Ajouter ici la gestion de:
		# - La meteo
		# - les revoltes
		# - l'adjudication de la region (si combat)

            ###################################
            # fin de gestion de la partie
            ###################################
            partie.tour += 1  # On avance dans les tours
            # Si plus de tour, la partie est finie
            if (partie.tour >= partie.finDePartie) : partie.run = False
            partie.put()

    def armeeAleatoire(nbOrdre,typeArmee,nombre):
        """Cree une armee en fonction du nombre de tour, d un type d armee et d un nombre max de combatant"""
        retour = ""
        nb = nombre
        armee = typeArmee[:]
        for t in range(nbOrdre):
            # la frappe
            retour += str(random.randint(0,2))+"_"
            if nb >= 0 :
                # le nombre de regiment et leur type
                n = random.randint(0,nb)
                for r in range(n): retour += armee[random.randint(0,len(armee)-1)]
                nb -= n
                
            if (t != (nbOrdre-1)) :  retour += "|"
            else:
                for r in range(0,nb):
                    retour += armee[random.randint(0,len(armee)-1)]
        
        return retour
  
    def sauveCombat(resultat,tour,region):
        resultatCombat = dbResultatCombat()
        resultatCombat.tour = tour
        resultatCombat.keyRegion = region.keyPartie.key()
        resultatCombat.resultat = resultat
        resultatCombat.put()	

    def deplaceArmee(self,nomJoueur,depart,arrivee):
        """Deplace l'armee d'un joueur"""
        resJ = self.cherche(dbJoueur,nomJoueur)
        if resJ == None : return -1
        resRD = self.cherche(dbRegion,depart)
        if resRD == None : return -1
        resRA = self.cherche(dbRegion,arrivee)
        if resRA == None : return -1

        # On ne deplace que l'armee du joueur qui est sur la bonne region
        a = dbArmee().all()
        a.filter("keyJoueur =", resJ.key())
        a.filter("keyRegion =", resRD.key())
        res = a.get()
        
        if (res):
            res.keyRegion = resRA.key()
            res.put()

    def setArmee(self,nomJoueur,sequence):
        """Met a jour l'armee d'un joueur a partir de son nom"""
        resJ = self.cherche(dbJoueur,nomJoueur)
        
        a = dbArmee().all()
        a.filter("keyJoueur =", resJ)
        res = a.get()
        if (res) :
            res.sequenceCombat = sequence
            res.put()

    def majCreArmee(cleArmee,cleRegion,sequenceCombat,regionDep):
        armee = dbArmee.all()
        armee.filter("__key__ =",db.Key(cleArmee))
        a = armee.get()

        a.sequenceCombat = sequenceCombat
        a.precedenteRegion = regionDep
        a.keyRegion = db.Key(cleRegion)
        
        a.put()

    ############################################################################
    ############################################################################
    ## Autres methodes
    ############################################################################
    ############################################################################
    def cherche(self,base,nom):
        """Recherche un poste a partir de Nom"""
        b = base().all()
        b.filter("nom =",nom)
        resB = b.get()
        if resB == None :   return -1
        else :              return resB
    
    ############################################################################
    ############################################################################
    ## Declarations statiques
    ############################################################################
    ############################################################################
    sauveCombat = staticmethod(sauveCombat)
    majCreArmee = staticmethod(majCreArmee)
    armeeAleatoire = staticmethod(armeeAleatoire)
    gereTour = staticmethod(gereTour)
    initGlobal = staticmethod(initGlobal)
    razBases = staticmethod(razBases)
    raz = staticmethod(raz)
